﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;

namespace ORMAC.Core
{
    internal class LinqParser
    {
        private Dictionary<ExpressionType, string> NodeType2SQL = new Dictionary<ExpressionType, string>
        {
            {ExpressionType.And,"and" },
            {ExpressionType.AndAlso,"and" },
            {ExpressionType.Or,"or" },
            {ExpressionType.OrElse,"or" },
            {ExpressionType.Equal,"=" },
            {ExpressionType.NotEqual,"<>" },
            {ExpressionType.GreaterThan,">" },
            {ExpressionType.LessThan,"<" },
            {ExpressionType.GreaterThanOrEqual,">=" },
            {ExpressionType.LessThanOrEqual,"<=" },
        };
        public string ParseSQLQuery<T>(Expression<Func<T, bool>> sqlLinq, IEnumerable<TableInfo> tables)
        {
            if (sqlLinq == null)
                return string.Empty;
            StringBuilder sb = new StringBuilder();
            InternalParseSQLQuery<T>(sqlLinq.Body, sb,tables.ToList<TableInfo>());
            return sb.ToString();
        }
        private void InternalParseSQLQuery<T>(Expression sqlLinq, StringBuilder res, List<TableInfo> tables)
        {
            if (sqlLinq is BinaryExpression)
            {
                BinaryExpression expression = sqlLinq as BinaryExpression;
                res.Append("(");
                InternalParseSQLQuery<T>(expression.Left, res,tables);
                res.Append(" ");
                res.Append(NodeType2SQL[expression.NodeType]);
                res.Append(" ");
                InternalParseSQLQuery<T>(expression.Right, res,tables);
                res.Append(")");
            }
            else if (sqlLinq is ConstantExpression)
            {
                ConstantExpression expression = sqlLinq as ConstantExpression;
                string formatStr = expression.Value is string ? "'{0}'" : "{0}";
                res.Append(string.Format(formatStr, expression.Value));
            }
            else if (sqlLinq is MemberExpression)
            {
                MemberExpression expression = sqlLinq as MemberExpression;
                TableInfo declaringTable = tables.Find(t => t.ClassType.Name == expression.Member.DeclaringType.Name);
                ColumnInfo declaringColumn =declaringTable.Columns.Find(c => c.PropertyName==expression.Member.Name);
                res.Append(declaringTable.Name+"."+ declaringColumn.DBName);
            }
        }

        internal string GetMemberName<T>(Expression<Func<T, object>> member)
        {
            if (member == null )
                return null;
            MemberExpression expr = member.Body as MemberExpression;
            if (expr == null)
                return null;
            return 
                expr.Member.Name;
        }
    }
}
